package com.xiyun.easyapi.service;

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.mybatisflex.core.query.QueryChain;
import com.mybatisflex.core.update.UpdateChain;
import com.xiyun.easyapi.annotation.CustomLog;
import com.xiyun.easyapi.config.util.ConvertUtil;
import com.xiyun.easyapi.config.util.Res;
import com.xiyun.easyapi.config.web.CustomException;
import com.xiyun.easyapi.controller.request.ModuleReq;
import com.xiyun.easyapi.controller.response.ModuleRes;
import com.xiyun.easyapi.dao.ModuleDao;
import com.xiyun.easyapi.mapper.ModuleMapper;
import com.xiyun.easyapi.mapper.ModulePermissionMapper;
import com.xiyun.easyapi.model.*;
import lombok.var;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
@CustomLog
@SuppressWarnings("all")
public class ModuleService {
    @Autowired
    private ModuleMapper moduleMapper;
    @Autowired
    private ModulePermissionMapper modulePermissionMapper;
    @Autowired
    private ModuleDao moduleDao;

    public Res<List<Module>> roots(ModuleReq.roots param) {
        return Res.success(() -> QueryChain.of(Module.class)
                .where(Module::getPid).eq(0)
                .orderBy(Module::getSort).asc()
                .list());
    }

    public Res<List<ModuleRes.modules>> root(ModuleReq.root param) {
        Module module = Optional.ofNullable(moduleMapper.selectOneById(param.getId()))
                .orElseThrow(() -> new CustomException("模块不存在"));
        List<ModuleRes.modules> modules;
        modules = moduleDao.modules(module.getTag());
        return Res.success(getTree(modules, param.getId()));
    }

    /**
     * 递归获取模块树
     *
     * @param list .
     * @param pid  .
     * @return .
     */
    private List<ModuleRes.modules> getTree(List<? extends Module> list, Long pid) {
        List<ModuleRes.modules> root = new ArrayList<>();
        list.forEach(module -> {
            if (!Objects.equals(module.getPid(), pid)) return;
            ModuleRes.modules item = ConvertUtil.copy(module, new ModuleRes.modules());
            root.add(item);
            List<ModuleRes.modules> tree = getTree(list, item.getId());
            item.setChildren(tree.isEmpty() ? null : tree);
        });
        return root;
    }

    /**
     * 保存模块
     *
     * @param param .
     * @return .
     */
    public Res<?> save(ModuleReq.save param) {
        return Res.success(() -> {
            Module module = ConvertUtil.copy(param, new Module());
            Module exisitModule = Optional.ofNullable(moduleMapper.selectOneById(param.getPid())).orElseThrow(() ->
                    new CustomException("父模块不存在")
            );
            exisitModule.setTag(exisitModule.getTag());
            moduleMapper.insertOrUpdate(module, true);
        });
    }

    /**
     * 删除模块
     *
     * @param param .
     * @return .
     */
    public Res<?> del(ModuleReq.del param) {
        return Res.success(() -> {
            Optional.ofNullable(moduleMapper.selectOneById(param.getId()))
                    .orElseThrow(() -> new CustomException("模块不存在"));
            moduleMapper.deleteById(param.getId());
        });
    }

    /**
     * 获取所有模块树
     *
     * @param param .
     * @return .
     */
    public Res<List<ModuleRes.modules>> all(ModuleReq.all param) {
        return Res.success(() -> {
            List<Module> list = QueryChain.of(Module.class)
                    .orderBy(Module::getSort).asc().list();
            return getTree(list, 0L);
        });
    }

    /**
     * 绑定接口权限
     *
     * @param param .
     * @return .
     */
    public Res<?> permission(ModuleReq.permission param) {
        return Res.success(() -> {
            Optional.ofNullable(moduleMapper.selectOneById(param.getId()))
                    .orElseThrow(() -> new CustomException("模块不存在"));
            UpdateChain.of(ModulePermission.class)
                    .where(ModulePermission::getModuleId).eq(param.getId())
                    .remove();
            List<ModulePermission> list = param.getPermission()
                    .stream()
                    .map(id -> new ModulePermission().setModuleId(param.getId())
                            .setPermissionId(id))
                    .collect(Collectors.toList());
            if (list.size() > 0) modulePermissionMapper.insertBatch(list);
        });
    }


    /**
     * 查询模块绑定的表和关联的接口及接口的校验规则
     *
     * @param param .
     * @return .
     */
    public Res<ModuleRes.getModuleTableInfo> getModuleTableInfo(ModuleReq.getModuleTableInfo param) {
        var res = new ModuleRes.getModuleTableInfo();
        Module exisitModule = Module.create().where(Module::getPath).eq(param.getPath()).oneOpt().orElseThrow(() ->
                new CustomException("模块不存在")
        );
        //填充参数信息
        String meta = exisitModule.getMeta();
        JSONArray array = JSONUtil.parseArray(meta);
        Object tableName = array.get(0);
        TableInfo exisitTableInfo = new TableInfo().select("table_comment", "info").where("table_name=?", tableName).oneOpt().orElseThrow(() ->
                new CustomException("模块未绑定表")
        );
        res.setTableInfo(JSONUtil.parse(exisitTableInfo.getInfo()));
        res.setTableName(exisitTableInfo.getTableComment());
        //查询绑定的接口
        var permissionInfo = QueryChain.of(ModulePermission.class).select("b.url as url", "b.name as name", "c.param as paramInfo", "c.param_valid as paramValid")
                .innerJoin(Permission.class).as("b").on("module_permission.permission_id = b.id and b.is_low_code = 1")
                .innerJoin(LowCodePermission.class).as("c").on("c.permission_id = module_permission.permission_id")
                .where(ModulePermission::getModuleId).eq(exisitModule.getId()).listAs(ModuleRes.getModuleTableInfo.item.class)
                .parallelStream().peek(e -> {
                    Object paramInfo = e.getParamInfo();
                    try {
                        paramInfo = JSONUtil.toBean(e.getParamInfo(), LinkedHashMap.class);
                    } catch (Exception ignored) {
                    }
                    e.setReq(paramInfo);
                    Object paramValid = e.getParamValid();
                    try {
                        paramValid = JSONUtil.toBean(paramValid.toString(), LinkedHashMap.class);
                    } catch (Exception ignored) {
                    }
                    e.setValid(paramValid);
                }).collect(Collectors.toList());
        res.setPermissionInfo(permissionInfo);

        return Res.success(res);
    }

}
